/**Transcore is a remote-GUI to Transmission.
Copyright (C) 2009 by Jerry de Swart

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package transcore;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

/**
 *
 * @author J de Swart (Custombuild@gmail.com)
 */
public class TransConnection {

	private URI transDaemonURI;
	private HttpClient client;
	private PostMethod postMethod;

	//TODO: Problematic login settings
	private String username;
	private String password;

	/**
	 * Constructor. Being called by createTransConnection because it throws Exception.
	 */
	private TransConnection() {
	}

	public static TransConnection createTransConnection(String host, int port, String username, String password) throws URISyntaxException {
		//Create a new TransConnection instance
		TransConnection conn = new TransConnection();

		//Create the URI to the transmission-host daemon URI
		URI transDaemonURI = new URI("http://" + username + ":" + password + "@" + host + ":" + port + "/transmission/rpc");
		conn.setTransDaemonSettings(transDaemonURI, username, password);

		conn.initConn();

		return conn;
	}

	public JSONObject send(JSONMessage messageOut) throws IOException, JSONException {
		postMethod = new PostMethod(transDaemonURI.toString());
		
		this.setRequestEntity(messageOut);

		int statusCode = client.executeMethod(postMethod);
		if (statusCode != HttpStatus.SC_OK) {
			//TODO: Error handling
			throw new IOException(HttpStatus.getStatusText(statusCode));
		}
		
		String responseBody = postMethod.getResponseBodyAsString();
		JSONTokener responseTokener = new JSONTokener(responseBody);
		JSONObject returnObject = (JSONObject) responseTokener.nextValue();

		String resultString = returnObject.getString("result");
		if (!resultString.equals("success")) {
            //TODO: Decent error handling
            throw new IOException("Request returned: " + resultString + "\nInvolved JSONMessage: " + messageOut.toString());
        }

		return returnObject;
	}

	public void setLogin(String username, String password) throws URISyntaxException {
		transDaemonURI = new URI("http://" + username + ":" + password + "@" + transDaemonURI.getHost() + ":" + transDaemonURI.getPort() + "/transmission/rpc");
		updateHttpStateCredentials();
	}

	private void updateHttpStateCredentials() {
		//TODO: Error handling when split doesn't result in 2 Strings.
		//TODO: Catch the situation where userInfo is null.. (When conn can't be made before?)
		/*String[] userinfo = transDaemonURI.getUserInfo().split(":");
		Credentials loginCreds = new UsernamePasswordCredentials(userinfo[0], userinfo[1]);*/
		Credentials loginCreds = new UsernamePasswordCredentials(username, password);
		client.getState().setCredentials(new AuthScope(transDaemonURI.getHost(), transDaemonURI.getPort(), AuthScope.ANY_REALM), loginCreds);
	}

	private void setClient(HttpClient client) {
		this.client = client;
	}

	private void setPostMethod(PostMethod postMethod) {
		this.postMethod = postMethod;
	}

	private void setTransDaemonSettings(URI transDaemonURI, String username, String password) {
		this.transDaemonURI = transDaemonURI;
		this.username = username;
		this.password = password;
	}

	private void setRequestEntity(JSONMessage messageOut) throws IOException {
		RequestEntity requestEntity = null;
		requestEntity = new StringRequestEntity(messageOut.toString(), "text/plain", "UTF-8");
		postMethod.setRequestEntity(requestEntity);
	}

	private void initConn() {
		client = new HttpClient();
		postMethod = new PostMethod(transDaemonURI.toString());

		//Login handling
		updateHttpStateCredentials();
	}
}
